home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / programr / upc12bs1.zip / LIB / winutil.c < prev    next >
C/C++ Source or Header  |  1993-10-02  |  12KB  |  331 lines

  1. /*--------------------------------------------------------------------*/
  2. /*       w i n u t i l . h                                            */
  3. /*                                                                    */
  4. /*       Windows 3.1 utility functions for UUPC/extended              */
  5. /*--------------------------------------------------------------------*/
  6.  
  7. /*--------------------------------------------------------------------*/
  8. /*       Copyright (c) Robert Denny, 1993                             */
  9. /*--------------------------------------------------------------------*/
  10.  
  11. /*--------------------------------------------------------------------*/
  12. /*       Changes Copyright (c) 1989-1993 by Kendra Electronic         */
  13. /*       Wonderworks.                                                 */
  14. /*                                                                    */
  15. /*       All rights reserved except those explicitly granted by       */
  16. /*       the UUPC/extended license agreement.                         */
  17. /*--------------------------------------------------------------------*/
  18.  
  19. /*--------------------------------------------------------------------*/
  20. /*                          RCS Information                           */
  21. /*--------------------------------------------------------------------*/
  22.  
  23. /*
  24.  *    $Id: winutil.c 1.5 1993/10/02 19:07:49 ahd Exp $
  25.  *
  26.  *    Revision history:
  27.  *    $Log: winutil.c $
  28.  * Revision 1.5  1993/10/02  19:07:49  ahd
  29.  * Print module name when winexec() fails
  30.  *
  31.  * Revision 1.4  1993/08/03  03:11:49  ahd
  32.  * Further Windows 3.x fixes
  33.  *
  34.  * Revision 1.3  1993/08/02  03:24:59  ahd
  35.  * Further changes in support of Robert Denny's Windows 3.x support
  36.  *
  37.  * Revision 1.2  1993/07/31  16:22:16  ahd
  38.  * Changes in support of Robert Denny's Windows 3.x support
  39.  *
  40.  * Revision 1.1  1993/07/22  23:19:50  ahd
  41.  * Initial revision
  42.  *
  43.  */
  44.  
  45. /*--------------------------------------------------------------------*/
  46. /*                        System include files                        */
  47. /*--------------------------------------------------------------------*/
  48.  
  49. #include <stdio.h>
  50. #include <stdlib.h>
  51. #include <string.h>
  52. #include <windows.h>
  53. #include <toolhelp.h>
  54.  
  55. /*--------------------------------------------------------------------*/
  56. /*                    UUPC/extended include files                     */
  57. /*--------------------------------------------------------------------*/
  58.  
  59. #include "lib.h"
  60. #include "winutil.h"
  61.  
  62. /*--------------------------------------------------------------------*/
  63. /*                           Local defines                            */
  64. /*--------------------------------------------------------------------*/
  65.  
  66. /*--------------------------------------------------------------------*/
  67. /*                          Private messages                          */
  68. /*--------------------------------------------------------------------*/
  69.  
  70. #define PM_TASKEND WM_USER
  71.  
  72. /*--------------------------------------------------------------------*/
  73. /*      Globals needed by callback functions & useful elsewhere       */
  74. /*--------------------------------------------------------------------*/
  75.  
  76. HTASK hOurTask;               // Our task handle
  77. HWND hOurWindow;              // Our EasyWin main window handle
  78.  
  79. /*--------------------------------------------------------------------*/
  80. /*                         Used only locally                          */
  81. /*--------------------------------------------------------------------*/
  82.  
  83. static HINSTANCE hChildInst;            // Instance of child proc
  84. static HWND hTheWindow;                 // Used by WindCatcher() during enumeration
  85.  
  86.  
  87. BOOL CALLBACK WindCatcher(HWND hWnd, LPARAM lparam);
  88. BOOL CALLBACK NotifyCatcher(WORD wID, DWORD dwData);
  89.  
  90. static LPFNNOTIFYCALLBACK lpfnNotifyCB;
  91. static FARPROC lpfnEnumWinCB;
  92.  
  93. void _DoneEasyWin(void);      // In TCWIN library
  94.  
  95. //------------------------------------------------------------------------
  96. //
  97. // CloseEasyWin() - Force EasyWin window to close on termination
  98. //
  99. // This function should be registered with a call to atexit() if
  100. // you want to force the EasyWin window to close, permitting the
  101. // application to exit, automatically. Normally, an EasyWin app
  102. // hangs out in the "inactive" state until the user manually closes
  103. // the window. Using an atexit() function assures that the app will
  104. // exit automatically, regardless of the means of generating the
  105. // exit action (such as Ctrl-SysReq signal handlers, etc.).
  106. //
  107. //------------------------------------------------------------------------
  108. void CloseEasyWin(void)
  109. {
  110.    MSG msg;
  111.  
  112.    //
  113.    // This will assure that the EasyWin task yields to the system
  114.    // at least once before exiting. See the comments next to the
  115.    // call to WinExec() below.
  116.    //
  117.    PeekMessage(&msg, hOurWindow, NULL, NULL, PM_NOREMOVE);
  118.    _DoneEasyWin();
  119. }
  120.  
  121.  
  122. //------------------------------------------------------------------------
  123. //
  124. // SpawnWait() - Spawn a child process, wait for termination
  125. //
  126. // Use WinExec() to fire off a child process, then synchronize with
  127. // its termination. For use with EasyWin applications.
  128. //
  129. // Inputs:
  130. //    cmdLine     Command line including executable name
  131. //    fuCmdShow   How to display new main window (see ShowWindow())
  132. //
  133. // Returns:
  134. //    -1          Big Trouble: NotifyRegister or WinExec failed
  135. //    >=0         Exit status of child
  136. //
  137. // On Error:
  138. //    Logs and displays an error message using printmsg()
  139. //
  140. //------------------------------------------------------------------------
  141.  
  142. int SpawnWait( const char *command,
  143.                const char *parameters,
  144.                const boolean synchronous,
  145.                const UINT fuCmdShow)
  146. {
  147.  
  148.    BOOL bChildIsExecuting = TRUE;
  149.    MSG msg;
  150.    int iChildExitStatus = 0;
  151.  
  152.    if ( synchronous )
  153.    {
  154.       lpfnNotifyCB = (LPFNNOTIFYCALLBACK)
  155.                            MakeProcInstance((FARPROC) NotifyCatcher,
  156.                                              _hInstance);
  157.  
  158.       if (!NotifyRegister(hOurTask, lpfnNotifyCB, NF_NORMAL))
  159.       {
  160.            FreeProcInstance(lpfnNotifyCB);
  161.            printmsg(0, "SpawnWait: NotifyRegister() failed.");
  162.            return(-1);
  163.       }
  164.    }
  165.  
  166.    //
  167.    // Start up the child proc with the given command line. To start a DOS
  168.    // box, use a .PIF file as the executable name (1st arg).
  169.    //
  170.    // WARNING! The spawned task MUST give up control to the system at
  171.    // least once before exiting! An EasyWin app that calls _DoneEasyWin()
  172.    // in an atexit() proc may never yiend to the system. In this case
  173.    // WinExec() will not return here before the spawned task terminates.
  174.    // The Notification callback will be called before WinExec() returns,
  175.    // and the hInstChild will not be set yet. Result: This task will never
  176.    // see the termination notfication of the spawned task, and SpawnWait()
  177.    // will wait forever. CAVEAT!
  178.    //
  179.    // (To insure we do yield, banner() has a call to ddelay().)
  180.  
  181.    if ( parameters == NULL )
  182.       hChildInst = WinExec( command , fuCmdShow);
  183.    else {
  184.       char buf[BUFSIZ];
  185.       strcpy( buf, command );
  186.       strcat( buf, " " );
  187.       strcat( buf, parameters );
  188.       hChildInst = WinExec( buf , fuCmdShow);
  189.    }
  190.  
  191.    if ( hChildInst < 32 )
  192.    {
  193.  
  194.       if ( synchronous )
  195.       {
  196.          NotifyUnRegister(hOurTask);
  197.          FreeProcInstance(lpfnNotifyCB);
  198.       }
  199.  
  200.       printmsg(0, "SpawnWait: WinExec(%s %s) failed. Code = %d\n",
  201.                   command,
  202.                   parameters ? parameters : "",
  203.                   (int)hChildInst);
  204.       return(-1);
  205.  
  206.    }  /* if */
  207.  
  208.    if ( ! synchronous )
  209.       return 0;
  210.  
  211.    //
  212.    // LOCAL MESSAGE LOOP - Service Windows while waiting for
  213.    // child proc to terminate.
  214.    //
  215.    while(bChildIsExecuting && GetMessage(&msg, NULL, NULL, NULL))
  216.    {
  217.       TranslateMessage(&msg);
  218.       DispatchMessage(&msg);
  219.  
  220.       if (msg.message == PM_TASKEND)
  221.       {
  222.          bChildIsExecuting = FALSE;
  223.          iChildExitStatus = (int)(LOBYTE(msg.lParam));
  224.       } /* while */
  225.  
  226.    } /* while */
  227.  
  228.    NotifyUnRegister(hOurTask);
  229.    FreeProcInstance(lpfnNotifyCB);
  230.  
  231.    return(iChildExitStatus);
  232.  
  233. } /* SpawnWait */
  234.  
  235. //------------------------------------------------------------------------
  236. //
  237. // NotifyCatcher() - Notification Callback
  238. //
  239. //------------------------------------------------------------------------
  240.  
  241. #ifdef __TURBOC__
  242. #pragma argsused
  243. #endif
  244.  
  245. BOOL CALLBACK NotifyCatcher (WORD wID, DWORD dwData)
  246. {
  247.    HTASK hCurTask;     // handle of the task that called the notification call back
  248.    TASKENTRY te;
  249.  
  250.  
  251.    // Check for task exiting
  252.    switch (wID)
  253.    {
  254.       case NFY_EXITTASK:
  255.          //
  256.          // Obtain info about the task that is terminating
  257.          //
  258.          hCurTask = GetCurrentTask();
  259.          te.dwSize = sizeof(TASKENTRY);
  260.          TaskFindHandle(&te, hCurTask);
  261.          //
  262.          // Check if the task that is terminating is our child task.
  263.          // Also check if the hInstance of the task that is terminating
  264.          // in the same as the hInstance of the task that was WinExec'd
  265.          // by us earlier in this file. This additional check is added
  266.          // because the Task List that is brought up by selecting
  267.          // 'Switch To ...' from the system menu is also run as a child
  268.          // task of the application and consequently the hInstance needs
  269.          // to be checked to determine which child task is terminating.
  270.          // Obviously, the parent may have intentionally WinExec'ed more
  271.          // than one child on purpose as well.
  272.          //
  273.          // Note that the PM_TASKEND message is sent with its LPARAM set
  274.          // to the dwData passed to this callback. The low byte of this
  275.          // is the child's exit status.
  276.          //
  277.          if (te.hTaskParent == hOurTask && te.hInst == hChildInst)
  278.             PostMessage(hOurWindow, PM_TASKEND, (WORD)hOurTask, dwData );
  279.  
  280.          break;
  281.  
  282.          default:
  283.             break;
  284.    }
  285.  
  286.    // Pass notification to other callback functions
  287.    return FALSE;
  288.  
  289. }
  290.  
  291. //------------------------------------------------------------------------
  292. //
  293. // FindTaskWindow() - Find handle to one of our windows, by name
  294. //
  295. //------------------------------------------------------------------------
  296. HWND FindTaskWindow (HTASK hTask, LPSTR lpszClassName)
  297. {
  298.  
  299.    hTheWindow = NULL;
  300.  
  301.    lpfnEnumWinCB = MakeProcInstance((FARPROC)WindCatcher, _hInstance);
  302.    EnumTaskWindows(hTask, lpfnEnumWinCB, (LPARAM)lpszClassName);
  303.    FreeProcInstance(lpfnEnumWinCB);
  304.  
  305.    return(hTheWindow);
  306. }
  307.  
  308.  
  309. //------------------------------------------------------------------------
  310. //
  311. // WindCatcher() - Callback function for EnumTaskWindows(). Passes
  312. //                 back a copy of the next window handle.
  313. //
  314. //------------------------------------------------------------------------
  315. #define BUF_LEN 32
  316. BOOL CALLBACK WindCatcher (HWND hWnd, LPARAM lparam)
  317. {
  318.     char buf[BUF_LEN+1];
  319.     int i;
  320.  
  321.     if ((i = GetClassName(hWnd, (LPSTR)buf, BUF_LEN)) == 0)
  322.        return(FALSE);                      // OOPS!
  323.     buf[i] = '\0';                          // Make cstr
  324.     if (lstrcmpi((LPCSTR)buf, (LPCSTR)lparam) == 0) // If we found it
  325.     {
  326.                 hTheWindow = hWnd;                  // Save it for called func
  327.         return(FALSE);
  328.     }
  329.     return(TRUE);
  330. }
  331.